// MileageTracker.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "MileageTracker.h"

static LRESULT CALLBACK MaskedEditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	WNDPROC pfnOldWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_USERDATA);

	// Process messages of interest
	switch (uMsg)
	{
		case WM_CHAR:
			if (iswdigit(wParam)	// digits
				|| wParam == '-'	// negativeSign
				|| wParam == '.'	// decimalSeparator
				|| wParam == '\b')	// backspace
				break; // This character is allowed
			else
				return 0; // This character isn't allowed
	}

	// Allow the original window procedure to process
	// the message.
	return CallWindowProc(pfnOldWndProc, hWnd, uMsg, wParam, lParam);
}

// Configure an edit control to only accept decimal data
static void SetupEditControl(HWND hDlg, int id, WCHAR * pszDefault)
{
	HWND hWndCtrl = GetDlgItem(hDlg, id);

	// Set the default value
	SetWindowText(hWndCtrl, pszDefault);

	// Store the current window procedure in the GWL_USERDATA field
	WNDPROC pfnOldWndProc = (WNDPROC)GetWindowLong(hWndCtrl, GWL_WNDPROC);
	SetWindowLong(hWndCtrl, GWL_USERDATA, (LONG)pfnOldWndProc);

	// Replace the window procedure with our one which 
	SetWindowLong(hWndCtrl, GWL_WNDPROC, (LONG)MaskedEditProc);
}

static void DrawLabel(HDC hDC, HWND hDlg, int id)
{
	// Get the static control's window handle
	HWND hWnd = GetDlgItem(hDlg, id);
	WCHAR szBuffer[64];
	RECT rcCtrl;

	// Figure out the location of the control
	// relative to the dialog's client area
	GetClientRect(hWnd, &rcCtrl);
	MapWindowPoints(hWnd, hDlg, (LPPOINT)&rcCtrl, 2);

	// Determine the text of the static control
	GetWindowText(hWnd, szBuffer, 64); 

	// Now paint the text onto the dialog
	SetBkMode(hDC, TRANSPARENT);
	DrawText(hDC, szBuffer, wcslen(szBuffer), &rcCtrl, DT_LEFT);
}

static double GetDecimal(HWND hDlg, int id)
{
	// Get the text stored in the text box
	WCHAR szBuffer[64];
	GetDlgItemText(hDlg, id, szBuffer, 64);

	// Convert it into a floating point number
	return wcstod(szBuffer, NULL);
}

static INT_PTR CALLBACK MileageTrackerDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_INITDIALOG:
            {
                SHINITDLGINFO shidi;
				SHMENUBARINFO mbi;

                // Create a Done button and size it.  
                shidi.dwMask = SHIDIM_FLAGS;
                shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
                shidi.hDlg = hDlg;
                SHInitDialog(&shidi);

				// Create a menu bar
                memset(&mbi, 0, sizeof(SHMENUBARINFO));
				mbi.cbSize     = sizeof(SHMENUBARINFO);
				mbi.hwndParent = hDlg;
				mbi.nToolBarId = IDR_MENU;
				mbi.hInstRes   = GetModuleHandle(NULL);
				mbi.dwFlags = SHCMBF_HMENU;
	            SHCreateMenuBar(&mbi);

				// Initialise the text boxes with default values
				SetupEditControl(hDlg, IDC_EDIT_DISTANCE, L"0");
				SetupEditControl(hDlg, IDC_EDIT_FUEL, L"0");
				SetupEditControl(hDlg, IDC_EDIT_PRICE, L"0");
				SetupEditControl(hDlg, IDC_EDIT_TANK, L"0");
			}
            return (INT_PTR)TRUE;

		case WM_PAINT:
			{
				RECT rcBounds;
				PAINTSTRUCT ps;
				TRIVERTEX vert[2];
				GRADIENT_RECT gRect;

				HDC hDC = BeginPaint(hDlg, &ps);

				GetClientRect(hDlg, &rcBounds);

				// Draw the solid bar at the top of the dialog
				rcBounds.bottom = rcBounds.top + 32;
				HBRUSH hBrush = CreateSolidBrush(RGB(64, 64, 255));
				FillRect(hDC, &rcBounds, hBrush);
				DeleteObject(hBrush);

				// Fill in the shaded area
				vert[0].x     = 0;
				vert[0].y     = rcBounds.bottom;
				vert[0].Red   = 0x8000;
				vert[0].Green = 0x8000;
				vert[0].Blue  = 0xff00;
				vert[0].Alpha = 0x0000;

				vert[1].x     = rcBounds.right;
				vert[1].y     = rcBounds.bottom + 64; 
				vert[1].Red   = 0xFF00;
				vert[1].Green = 0xFF00;
				vert[1].Blue  = 0xFF00;
				vert[1].Alpha = 0x0000;

				gRect.UpperLeft  = 0;
				gRect.LowerRight = 1;
				GradientFill(hDC, vert, 2, &gRect, 1, GRADIENT_FILL_RECT_V);

				// Draw the labels over top of the shaded background
				DrawLabel(hDC, hDlg, IDC_LABEL_DISTANCE);
				DrawLabel(hDC, hDlg, IDC_LABEL_FUEL);
				DrawLabel(hDC, hDlg, IDC_LABEL_PRICE);
				DrawLabel(hDC, hDlg, IDC_LABEL_TANK);

				EndPaint(hDlg, &ps);
			}
			return TRUE;

        case WM_COMMAND:
			switch (LOWORD(wParam))
			{
				case IDOK:
		            EndDialog(hDlg, LOWORD(wParam));
			        return (INT_PTR)TRUE;

				case ID_CALCULATE:
					{
						WCHAR szBuffer[512];
						double milesPerGallon = 0;
						double gallonsPer100Miles = 0;
						double maximumRange;
						double costPer100Miles;

						// Obtain the input parameters from the user interface
						double distance = GetDecimal(hDlg, IDC_EDIT_DISTANCE);
						double fuel = GetDecimal(hDlg, IDC_EDIT_FUEL);
						double price = GetDecimal(hDlg, IDC_EDIT_PRICE);
						double tank = GetDecimal(hDlg, IDC_EDIT_TANK);
						
						// Perform the calculations
						if(fuel != 0)
							milesPerGallon = distance / fuel;
						
						if (milesPerGallon != 0)
							gallonsPer100Miles = 100 / milesPerGallon;
						
						costPer100Miles = gallonsPer100Miles * price;
						maximumRange = tank * milesPerGallon;

						// Format the results and update the user interface
						swprintf(szBuffer, L"Miles Per Gallon: %0.2f Mpg\r\n\r\n"
							L"%0.2f Gallons Per 100 Miles\r\n\r\n"
							L"$%0.2f Per 100 Miles\r\n\r\n"
							L"Maximum Range: %0.2f Miles",
							milesPerGallon, gallonsPer100Miles,
							costPer100Miles, maximumRange);

						SetDlgItemText(hDlg, IDC_EDIT_RESULTS, szBuffer);
					}
					break;

				case ID_CLEAR:
					// Reset all controls to default values
					SetDlgItemText(hDlg, IDC_EDIT_DISTANCE, L"0");
					SetDlgItemText(hDlg, IDC_EDIT_FUEL, L"0");
					SetDlgItemText(hDlg, IDC_EDIT_PRICE, L"0");
					SetDlgItemText(hDlg, IDC_EDIT_TANK, L"0");
					SetDlgItemText(hDlg, IDC_EDIT_RESULTS, L"");
					break;
            }
            break;

        case WM_CLOSE:
            EndDialog(hDlg, message);
            return (INT_PTR)TRUE;

    }
    return (INT_PTR)FALSE;
}

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   int       nCmdShow)
{
	SHInitExtraControls();

	return DialogBox(hInstance, (LPCTSTR)IDD_MILEAGETRACKER, NULL, MileageTrackerDialog);
}
